#include <ClanLib/core.h>
#include <ClanLib/application.h>
#include <ClanLib/display.h>
#ifdef USE_SDL
	#include <ClanLib/sdl.h>
#else
	#include <ClanLib/gl.h>
#endif
#include "viewport.h"
#include "entity.h"

// Viewport

Viewport::Viewport()
{
}

Viewport::Viewport(CL_Rect &world, CL_Rect &screen, CL_GraphicContext **displayWindow)
{
	world_area = world;
	screen_area = screen;
	window_gc = displayWindow;
}

Viewport::Viewport(CL_Rect &world, CL_Rect &screen, CL_GraphicContext **displayWindow, Entity &target, CL_Rect &bounds)
{
	world_area = world;
	screen_area = screen;
	window_gc = displayWindow;
	setTarget(target);
	pan_bounds = bounds;//CL_Rect(0,0,800,480);
	
	CL_Size worldSize = world_area.get_size();
	pan_bounds.right -= worldSize.width;
	pan_bounds.bottom -= worldSize.height;
	//std::cout << "constructor: " << pan_bounds.top << "," << pan_bounds.left << std::endl;
}

Viewport::~Viewport()
{
}

// set following target
void Viewport::setTarget(Entity &newTarget)
{
  target = &newTarget;
}

// clear following target
void Viewport::clearTarget()
{
  target = NULL;
}

// update viewport to follow target 
void Viewport::update()
{
  if(target != NULL){
    CL_Point newPos;
    CL_Size currentSize = world_area.get_size();
    newPos.x = target->pos.x - (currentSize.width/2);
    newPos.y = target->pos.y - (currentSize.height/2);
    //CL_Rect an_bounds = CL_Rect(0,0,800,480);
    if(newPos.x < pan_bounds.left) newPos.x = pan_bounds.left;
    if(newPos.y < pan_bounds.top) newPos.y = pan_bounds.top;
    if(newPos.x > pan_bounds.right) newPos.x = pan_bounds.right;
    if(newPos.y > pan_bounds.bottom) newPos.y = pan_bounds.bottom;
    //std::cout << pan_bounds.right << "," << pan_bounds.bottom << std::endl;

    //std::cout << "Bounds ( " << pan_bounds.left << ", " << pan_bounds.top << ")" << std::endl;
    //if(newPos.x < 0) newPos.x = 0;
    //if(newPos.y < 0) newPos.y = 0;
    //if(newPos.x > 800 - currentSize.width) newPos.x = 800 - currentSize.width;
    //if(newPos.y > 480 - currentSize.height) newPos.y = 480 - currentSize.height;
        
    world_area = CL_Rect(newPos, currentSize);
  }
}

// translate world coordinates represented by world_area to corresponding screen coordinates
void Viewport::worldToScreen(CL_Rect &rect)
{
	// convert dest to screen coordinates
	if(screen_area.get_size() == world_area.get_size())
	{
		// just translate coordinates if scale is the same
		rect.left = (rect.left - world_area.left) + screen_area.left;
		rect.right = (rect.right - world_area.left) + screen_area.left;
		rect.top = (rect.top - world_area.top) + screen_area.top;
		rect.bottom = (rect.bottom - world_area.top) + screen_area.top;
	}
	else
	{
		// translate and scale coordinates
		rect.left = (rect.left - world_area.left) * screen_area.get_width();
		rect.right = (rect.right - world_area.left) * screen_area.get_width();
		rect.top = (rect.top - world_area.top) * screen_area.get_height();
		rect.bottom = (rect.bottom - world_area.top) * screen_area.get_height();

		rect.left = (rect.left / world_area.get_width()) + screen_area.left;
		rect.right = (rect.right / world_area.get_width()) + screen_area.left;
		rect.top = (rect.top / world_area.get_height()) + screen_area.top;
		rect.bottom = (rect.bottom / world_area.get_height()) + screen_area.top;			
	}
}

// draw area of surface described by src to screen equivalent of world coordinates described by dest
void Viewport::draw(CL_Surface &surface, CL_Rect &src, CL_Rect dest)
{
	// convert destination coordinates from world coordinates to screen coordinates
	worldToScreen(dest);
	
	// clip draws to viewport screen area
	if((*window_gc)->get_cliprect() != screen_area)
		(*window_gc)->set_cliprect( screen_area );

	// draw to screen
	surface.draw_subpixel( src, dest, *window_gc);
}

// draw area of surface described by src to background
void Viewport::draw(CL_Surface &surface, CL_Rect &src)
{	
	// clip draws to viewport screen area
	if((*window_gc)->get_cliprect() != screen_area)
		(*window_gc)->set_cliprect( screen_area );

	// draw to screen
	surface.draw_subpixel( src, screen_area, *window_gc);
}


// draw surface to background
void Viewport::draw(CL_Surface &surface)
{	
	// clip draws to viewport screen area
	if((*window_gc)->get_cliprect() != screen_area)
		(*window_gc)->set_cliprect( screen_area );

	// draw to screen
	surface.draw(screen_area, *window_gc);
}

// draw area of surface described by src to screen equivalent of world coordinates described by dest
void Viewport::draw(CL_Sprite &sprite, CL_Rect dest)
{
	// convert destination coordinates from world coordinates to screen coordinates
	worldToScreen(dest);
	
	// clip draws to viewport screen area
	if((*window_gc)->get_cliprect() != screen_area)
		(*window_gc)->set_cliprect( screen_area );

	// draw to screen
	sprite.draw(dest, (*window_gc));
}

const CL_Rect &Viewport::get_world_area()
{
	return world_area;
}

const CL_Rect &Viewport::get_screen_area()
{
	return screen_area;
}

CL_GraphicContext **Viewport::get_window_gc()
{
	return window_gc;
}
